package com.example.demojenkins.filter;

import cn.hutool.json.JSONUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Map;

/**
 * @version 1.0
 * @author: LZ
 * @description:
 * @since 2025-06-19 14:51
 */
public class RequestLoggingFilter implements Filter{
    private static final Logger logger = LoggerFactory.getLogger(RequestLoggingFilter.class);

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {

        // 将ServletRequest转换为HttpServletRequest，以便获取请求URL和方法
        HttpServletRequest httpRequest = (HttpServletRequest) request;

        // 获取请求的URL
        String requestURI = httpRequest.getRequestURI();
        //请求方法
        String method = httpRequest.getMethod();

        // 验证方法名是否合法（仅允许 ASCII 字母、数字、连字符）
        if (!method.matches("^[A-Za-z0-9-]+$")) {
            logger.warn("Invalid HTTP method: {}", method);
            HttpServletResponse httpResponse = (HttpServletResponse) response;
            httpResponse.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid HTTP method");
            return;
        }
        //请求参数
        Map<String, String[]> params = request.getParameterMap();

        // 获取客户端IP地址
        String clientIp = getClientIpAddress(httpRequest);

        // 记录请求信息
        logger.info("请求方式: {} 请求地址: {} 来自于 IP: {} 请求参数: {} ", method, requestURI, clientIp, JSONUtil.toJsonStr(params));

        // 继续执行过滤器链
        chain.doFilter(request, response);
    }

    /**
     * 获取客户端真实IP地址
     * 考虑了代理服务器的情况
     */
    private String getClientIpAddress(HttpServletRequest request) {
        // 检查常见的代理头
        String xffHeader = request.getHeader("X-Forwarded-For");
        if (xffHeader == null) {
            // 如果没有代理头，直接返回RemoteAddr
            return request.getRemoteAddr();
        }
        // 对于多级代理，X-Forwarded-For的格式为: clientIp, proxy1Ip, proxy2Ip...
        // 取第一个IP地址作为客户端真实IP
        return xffHeader.split(",")[0].trim();
    }
}
